﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WMSSoft.Lib.Basic;
using WMSSoft.Lib.Const;
using WMSSoft.Lib.Interfaces;
using WMSSoft.Lib.WinKStart.Model.MenuConfig;

namespace WMSSoft.Lib.WinKStart
{
    public delegate void SearchEngineUpdate_EventHandler(object sender, iWinKStartSearchEngine e); 

    public class cSearchEnginesReader
    {
        private Dictionary<string, SearchEngineItem> _SearchItems = null;

        public event SearchEngineUpdate_EventHandler UpdatedSearchEngine;

        public cSearchEnginesReader()
        {
            //Initialise
            _SearchItems = new Dictionary<string, SearchEngineItem>();
        }

        #region Properties

        public Dictionary<string, SearchEngineItem> SearchEngines
        {
            get { return _SearchItems; }
        }

        #endregion

        #region Public Methods
        public iWinKStartSearchEngine GetSearchEngineInstance(string SearchEngine)
        {
            if (_SearchItems.ContainsKey(SearchEngine) == true)
            {
                return _SearchItems[SearchEngine].InstanceSearchEngineItem;
            }
            else throw new Exception("SeachEngine doesn't exist!");            
        }

        /// <summary>
        /// Load Search Engines from XML Configuration (XML Node)
        /// </summary>
        /// <param name="Node">Node to load Configuration from</param>
        public void Load(System.Xml.XmlNode Node)
        {
            try
            {
                SearchEngineItem oSearchEngine = null;

                foreach (System.Xml.XmlNode Item in Node.ChildNodes)
                {
                    if (Item.Name == XMLNodeNames.DATASOURCE_XMLNODE__ADDSEARCHENGINE)
                    {
                        oSearchEngine = null;

                        oSearchEngine = MakeSearchEngine(Item);

                        if (oSearchEngine != null)
                        {
                            _SearchItems.Add(oSearchEngine.Name, oSearchEngine);
                        }
                    }
                }
            }
            catch (Exception Ex)
            {
                CMessagelogging.AppendMessage("Can't load SearchEngines!", Ex, EMessageTypes.Error);
            }
        }

        /// <summary>
        /// Instantiate the Named Search Engine
        /// </summary>
        /// <param name="SearchEngine">Search Engine to Instantiate</param>
        /// <returns></returns>
        public bool InitSearchEngine(string SearchEngine)
        {
            try
            {
                if (_SearchItems != null && _SearchItems.Count() > 0 && _SearchItems.ContainsKey(SearchEngine) == true)
                {
                    SearchEngineItem tmpSearchEngine = _SearchItems[SearchEngine];
                    //Create instance for this
                    if (tmpSearchEngine.InstanceSearchEngineItem == null)
                    {
                        string tmpDataSourcesPath = System.IO.Path.Combine(cUserSettingsReader.SearchEnginesPath, tmpSearchEngine.Assembly);
                        System.Reflection.Assembly tmpAssembly = System.Reflection.Assembly.LoadFile(tmpDataSourcesPath);
                        iWinKStartSearchEngine tmpSEInstance = (iWinKStartSearchEngine)tmpAssembly.CreateInstance(tmpSearchEngine.ClassName);

                        tmpSEInstance.Assembly = tmpSearchEngine.Assembly;
                        tmpSEInstance.ClassName = tmpSearchEngine.ClassName;
                        tmpSEInstance.DataSourceName = tmpSearchEngine.DataSource;
                        tmpSEInstance.Name = tmpSearchEngine.Name;
                        tmpSEInstance.ShortName = tmpSearchEngine.ShortName;

                        tmpSearchEngine.InstanceSearchEngineItem = tmpSEInstance;
                    }
                    return true;
                }
                else return false;
                
            }
            catch (Exception Ex)
            {
                throw new Exception("Can't Initialize Search Engine '" + SearchEngine + "'!", Ex);
            }
        }

        /// <summary>
        /// Search after in Pattern given Text using named search engine
        /// </summary>
        /// <param name="SearchEngine">SearchEngine to use</param>
        /// <param name="Pattern">Text to search</param>
        public void Search(string SearchEngine, string Pattern, int DefaultMaxItems = 5)
        {
            try
            {
                if (_SearchItems.ContainsKey(SearchEngine) == true)
                {
                    if (_SearchItems[SearchEngine].InstanceSearchEngineItem == null) InitSearchEngine(SearchEngine);

                    if (_SearchItems[SearchEngine].InstanceSearchEngineItem != null)
                    {
                        _SearchItems[SearchEngine].InstanceSearchEngineItem.SearchCompleted += InstanceSearchEngineItem_SearchCompleted;
                        _SearchItems[SearchEngine].InstanceSearchEngineItem.Search(Pattern, DefaultMaxItems);
                    }
                }
            }
            catch (Exception Ex)
            {
                throw new Exception("Can't Search Text with given Search Engine '" + SearchEngine + "'!", Ex);
            }
        }

        void InstanceSearchEngineItem_SearchCompleted(object sender, EventArgs e)
        {
            try
            {
                if (UpdatedSearchEngine != null) UpdatedSearchEngine(sender, (iWinKStartSearchEngine)sender);
            }
            catch (Exception Ex)
            {
                throw new Exception("Error while fire event SearchCompleted!", Ex);
            }
        }

        /// <summary>
        /// Stop all running thread from SearchEngines
        /// </summary>
        /// <returns></returns>
        public bool Unload()
        {
            try
            {
                Dictionary<string, SearchEngineItem>.KeyCollection KeysSearchEngines = _SearchItems.Keys;
                foreach (string KeyItem in KeysSearchEngines)
                {
                    if (_SearchItems[KeyItem].InstanceSearchEngineItem != null)
                    {
                        _SearchItems[KeyItem].InstanceSearchEngineItem.StopWorking();
                    }
                }
                return true;
            }
            catch (Exception Ex)
            {
                throw new Exception("Can't complete unload search engines!", Ex);
            }
        }

        #endregion

        #region Private Methods
        private SearchEngineItem MakeSearchEngine(System.Xml.XmlNode Node)
        {
            try
            {
                string sName = "", sShortName = "", sAssembly = "", sClassName = "", sDatasource = "", sFilter = "";

                if (Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__NAME] != null)
                {
                    sName = Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__NAME].InnerText;
                }

                if (Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__SHORTNAME] != null)
                {
                    sShortName = Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__SHORTNAME].InnerText;
                }

                if (Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__ASSEMBLY] != null)
                {
                    sAssembly = Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__ASSEMBLY].InnerText;
                }

                if (Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__CLASSNAME] != null)
                {
                    sClassName = Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__CLASSNAME].InnerText;
                }

                if (Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__DATASOURCE] != null)
                {
                    sDatasource = Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__DATASOURCE].InnerText;
                }

                if (Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__FILTER] != null)
                {
                    sFilter = Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__FILTER].InnerText;
                }

                return new SearchEngineItem(sName, sShortName, sAssembly, sClassName, sDatasource, sFilter);
                
            }
            catch
            {
                return null;
            }
        }
        #endregion
    }
}
